# frozen_string_literal: true

require 'fast_spec_helper'

RSpec.describe 'gitlab:openapi namespace rake tasks', :silence_stdout, feature_category: :api do
  before :all do
    Rake.application.rake_require 'tasks/gitlab/openapi'
    Rake::Task.define_task(:environment)
    Rake::Task.define_task(:enable_feature_flags)
  end

  let(:yaml_doc_introduction) do
    <<~INTRO
    #############################################################################################
    # This documentation is auto-generated by a script.                                         #
    # Please do not edit this file directly.                                                    #
    #                                                                                           #
    # To edit the introductory text, modify `lib/tasks/gitlab/openapi.rake`.                    #
    #                                                                                           #
    # Run `bin/rake gitlab:openapi:generate`                                                    #
    #############################################################################################

    INTRO
  end

  describe 'gitlab:openapi:generate' do
    let(:json_content) { '{"key": "value"}' }
    let(:yaml_content) { "---\nkey: value\n" }

    before do
      allow(Rake::Task['oapi:fetch']).to receive(:invoke)
      allow(File).to receive(:read).with('tmp/openapi_swagger_doc.json').and_return(json_content)
      allow(File).to(
        receive(:read).with(Rails.root.join('deprecations/tasks/gitlab/openapi_rake.yml').to_s).and_call_original
      )
    end

    it 'generates the OpenAPI documentation' do
      expect(ENV).to receive(:[]=).with('store', 'tmp/openapi.json')
      expect(Rake::Task['oapi:fetch']).to receive(:invoke).with(['openapi.json'])
      expect(File).to receive(:write).with(
        'doc/api/openapi/openapi_v2.yaml',
        yaml_doc_introduction + yaml_content
      )

      run_rake_task('gitlab:openapi:generate')
    end

    context 'when not on test or development environments' do
      before do
        allow(Rails).to receive_message_chain(:env, :test?).and_return(false)
        allow(Rails).to receive_message_chain(:env, :development?).and_return(false)
      end

      it 'raises an error' do
        expect { run_rake_task('gitlab:openapi:generate') }
          .to raise_error(RuntimeError, 'This task can only be run in the development or test environment')
      end
    end
  end

  describe 'gitlab:openapi:check_docs' do
    let(:documentation) { {} }

    before do
      allow(Rake::Task['oapi:fetch']).to receive(:invoke)
      allow(File).to receive(:read).and_call_original
      allow(File).to receive(:read).with('tmp/openapi_swagger_doc.json').and_return('{}')
      allow(File).to receive(:read).with('doc/api/openapi/openapi_v2.yaml')
        .and_return(yaml_doc_introduction + documentation.to_yaml)
    end

    it 'passes when documentation is up to date' do
      expect { run_rake_task('gitlab:openapi:check_docs') }.to output(/OpenAPI documentation is up to date/).to_stdout
    end

    context 'when documentation is outdated' do
      let(:documentation) { { 'outdated' => true } }

      it 'aborts when documentation is outdated' do
        expect { run_rake_task('gitlab:openapi:check_docs') }.to raise_error(SystemExit)
      end

      it 'outputs correct message when documentation is outdated' do
        expected_output = /OpenAPI documentation is outdated!/

        expect { run_rake_task('gitlab:openapi:check_docs') }.to output(expected_output).to_stdout
          .and raise_error(SystemExit)
      end
    end

    context 'when debug is enabled' do
      let(:documentation) { { 'outdated' => true } }
      let(:verbose) { Rake::FileUtilsExt.verbose }
      let(:nowrite) { Rake::FileUtilsExt.nowrite }

      before do
        stub_env('OPENAPI_CHECK_DEBUG', 'true')

        Rake::FileUtilsExt.verbose(false)
        Rake::FileUtilsExt.nowrite(true)
      end

      after do
        Rake::FileUtilsExt.verbose(verbose)
        Rake::FileUtilsExt.nowrite(nowrite)
      end

      it 'outputs a diff' do
        expected_command = 'diff -u doc/api/openapi/openapi_v2.yaml doc/api/openapi/openapi_v2.yaml.generated'

        expect(main_object).to receive(:sh).with(expected_command).and_return(true)
        expect { run_rake_task('gitlab:openapi:check_docs') }.to raise_error(SystemExit)
      end
    end
  end
end
